Skip to content

KaTeX (2/n): Support horizontal and vertical offsets for spans #1452

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

rajveermalviya
Copy link
Member

Stacked on top of: #1408

Web Flutter
Screenshot 2025-04-01 at 22 08 22 Screenshot 2025-04-01 at 22 09 00

Related: #46

Comment on lines +372 to +376
sealed class KatexNode extends ContentNode {
const KatexNode({super.debugHtmlNode});
}

class KatexSpanNode extends KatexNode {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One point that I noticed while developing #1478 (and checking how my draft of that branch interacted with this PR): it'd be good for this commit:
e268041 content: Handle vertical offset spans in KaTeX content

to get split up like so:

  • First, an NFC prep commit introduces the distinction between KatexNode and KatexSpanNode. At this stage, the latter is the only subclass of the former.
  • Then another commit makes the substantive changes this commit is about, including introducing the sibling subclasses KatexVlistNode and KatexVlistRowNode.

One reason that'd be useful is that the split between KatexNode and KatexSpanNode is somewhat nontrivial in itself: some of the references to KatexNode continue to say KatexNode, while others switch to saying KatexSpanNode, so the commit is expressing meaningful information by its choices of which references go which way.

@rajveermalviya rajveermalviya force-pushed the pr-tex-content-2 branch 2 times, most recently from b17033a to 16cb28f Compare April 24, 2025 08:21
This applies the correct font scaling if the KaTeX content is
inside a header.
And rename previous type to KatexSpanNode, also while making it a
subtype of KatexNode.
Implement handling most common types of `vlist` spans.
Negative margin spans on web render to the offset being applied
to the specific span and all the adjacent spans, so mimic the
same behaviour here.
@gnprice gnprice added the maintainer review PR ready for review by Zulip maintainers label Apr 29, 2025
@gnprice
Copy link
Member

gnprice commented Apr 29, 2025

It seems like this had slipped through the cracks :-) but it looks ready for review, so I applied the label.

Also rebased now that #1478 is merged, so this now contains only the changes that are specific to this PR.

Copy link
Member

@PIG208 PIG208 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I think the last few commits will need some tests for the more complicated parts. I went over the changes and left some comments, but haven't extensively tested the changes manually yet.

Comment on lines +525 to +526
_logError('KaTeX: Unsupported CSS property: $property of '
'type ${expression.runtimeType}');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One other possibility for this to be logged is when _getEm returns null. I think for debugging purpose, including the value expression might be helpful.

if (expression is css_visitor.EmTerm && expression.value is num) {
return (expression.value as num).toDouble();
}
return null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's perhaps have a short dartdoc on what this does and what null means, since the if (…Em != null) continue;'s make this return value quite relevant.

Comment on lines +570 to +573
final double? heightEm;
final double? marginRightEm;
final double? topEm;
final double? verticalAlignEm;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good idea to separate them into groups; to add on this, how about having a short comment before each group explaining how we group them together (like we do with design variables)?

}

return Container(
margin: styles.marginRightEm != null && !styles.marginRightEm!.isNegative
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, !styles.marginRightEm!.isNegative seems a bit contrived. I think isNegative negated is not as clear as >= 0. However, do we need the margin when marginRightEm is 0?

Comment on lines +481 to +483
styles: inlineStyles != null
? styles.merge(inlineStyles)
: styles,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having tests for this (the case when there are both inline styles and others) might be useful. Not sure how common that is.

Comment on lines +987 to +997
child: RichText(text: TextSpan(
children: List.unmodifiable(row.nodes.map((e) {
return WidgetSpan(
alignment: PlaceholderAlignment.baseline,
baseline: TextBaseline.alphabetic,
child: switch (e) {
KatexSpanNode() => _KatexSpan(e),
KatexVlistNode() => _KatexVlist(e),
KatexNegativeMarginNode() => _KatexNegativeMargin(e),
});
})))));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like this can be replaced with _KatexNodeList(nodes: row.nodes)

Comment on lines +1013 to +1023
child: Text.rich(TextSpan(
children: List.unmodifiable(node.nodes.map((e) {
return WidgetSpan(
alignment: PlaceholderAlignment.baseline,
baseline: TextBaseline.alphabetic,
child: switch (e) {
KatexSpanNode() => _KatexSpan(e),
KatexVlistNode() => _KatexVlist(e),
KatexNegativeMarginNode() => _KatexNegativeMargin(e),
});
})))));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_KatexNodeList also seems helpful here.

}

class _KatexNegativeMargin extends StatelessWidget {
const _KatexNegativeMargin(this.node);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the name implies that the margin should be negative, maybe we should also add assertions to ensure that that is true.

Comment on lines 125 to 149
List<KatexNode> _parseChildSpans(dom.Element element) {
return List.unmodifiable(element.nodes.map((node) {
if (node case dom.Element(localName: 'span')) {
return _parseSpan(node);
} else {
var resultSpans = <KatexNode>[];
for (final node in element.nodes.reversed) {
if (node is! dom.Element || node.localName != 'span') {
throw KatexHtmlParseError();
}
}));

final span = _parseSpan(node);
resultSpans.add(span);

if (span is KatexSpanNode) {
final marginRightEm = span.styles.marginRightEm;
if (marginRightEm != null && marginRightEm.isNegative) {
final previousSpansReversed =
resultSpans.reversed.toList(growable: false);
resultSpans = [];
resultSpans.add(KatexNegativeMarginNode(
marginRightEm: marginRightEm,
nodes: previousSpansReversed));
}
}
}

return resultSpans.reversed.toList(growable: false);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat solution! A bit tricky to understand. I think we can use QueueList (and with .addFirst) to avoid the hassle of reversing and unreversing the list.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be helpful to have tests for this.

final pstrutStyles = _parseSpanInlineStyles(pstrutSpan)!;
final pstrutHeight = pstrutStyles.heightEm ?? 0;

// TODO handle negative right-margin inline style on row nodes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we consider this complete after the final commit ("content: Support negative right-margin on KaTeX spans")? I'm not too sure if something else is left to be done here.

This seems to contradict with the earlier assumption that vlist elements contain only the height style.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maintainer review PR ready for review by Zulip maintainers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants